@using BlazorDatasheet.DataStructures.Geometry
@using BlazorDatasheet.Render
@using BlazorDatasheet.Util
@using Microsoft.AspNetCore.Components.Web.Virtualization;
@using System.Text
@using BlazorDatasheet.Core.Data
@using BlazorDatasheet.Core.Events.Layout
@using BlazorDatasheet.DataStructures.Intervals
@using BlazorDatasheet.Events

<div style="position: absolute; top: 0; left: 0;">

    @foreach (var interval in _selectionIntervals)
    {
        <BoxOverlayRenderer
            BackgroundVisible="@true"
            BorderThickness="0"
            BackgroundStyle="background:var(--selection-bg-color);"
            Width="CellLayoutProvider.ComputeWidth(-1, 1)"
            Height="CellLayoutProvider.ComputeHeight(interval.Start, interval.Length)"
            X="CellLayoutProvider.ComputeLeftPosition(-1)"
            Y="CellLayoutProvider.ComputeTopPosition(interval.Start)"/>
    }

</div>

@for (int rowIndex = VisibleRowStart; rowIndex < (VisibleRowStart + NVisibleRows); rowIndex++)
{
    var row = rowIndex;
    var heading = @Sheet.Rows.GetHeading(row) ?? (row + 1).ToString();
    <div class="sheet-row">
        <div
            class="sheet-cell row-head @(IsActive(row) ? "row-active" : "")"
            style="height:@CellLayoutProvider.ComputeHeight(row, 1)px; 
            overflow: hidden; 
            display: block !important; 
            @CssUtil.GetCellWidthStyles(-1, 1, CellLayoutProvider)"
            @onmousedown="e => HandleMouseDown(row, e)"
            @onmouseover="e => HandleMouseOver(row, e)"
            @onmouseup="e => HandleMouseUp(row, e)">
            <div class="cell" style="text-align: right">
                @heading
            </div>
        </div>
    </div>
}


@code {

    private Sheet? _sheet;

    [Parameter, EditorRequired]
    public Sheet? Sheet { get; set; }

    [Parameter, EditorRequired]
    public CellLayoutProvider CellLayoutProvider { get; set; }

    [Parameter, EditorRequired]
    public EventCallback<RowMouseEventArgs> OnMouseUp { get; set; }

    [Parameter, EditorRequired]
    public EventCallback<RowMouseEventArgs> OnMouseOver { get; set; }

    [Parameter, EditorRequired]
    public EventCallback<RowMouseEventArgs> OnMouseDown { get; set; }

    [Parameter, EditorRequired]
    public int VisibleRowStart { get; set; }

    [Parameter, EditorRequired]
    public int NVisibleRows { get; set; }

    private List<OrderedInterval> _selectionIntervals = new();

    private bool IsActive(int row)
    {
        return (Sheet!.Selection.SelectingRegion?.SpansRow(row) == true)
               || Sheet!.Selection.Regions.Any(x => x.SpansRow(row));
    }

    protected override void OnParametersSet()
    {
        if (_sheet != Sheet)
        {
            if (_sheet != null)
            {
                _sheet.Selection.SelectingChanged -= OnSelectingChanged;
                _sheet.Selection.SelectionChanged -= OnSelectionChanged;
            }
            _sheet = Sheet;
            
            if (_sheet == null)
                return;
            
            _sheet.Selection.SelectingChanged += OnSelectingChanged;
            _sheet.Selection.SelectionChanged += OnSelectionChanged;
        }
        base.OnParametersSet();
    }

    private void OnSelectionChanged(object? sender, IEnumerable<IRegion> e) => UpdateIntervals();

    private void OnSelectingChanged(object? sender, IRegion? region) => UpdateIntervals();

    private void UpdateIntervals()
    {
        StateHasChanged();
    }

    private void HandleMouseUp(int row, MouseEventArgs args)
    {
        OnMouseUp.InvokeAsync(new RowMouseEventArgs(row, args));
    }

    private void HandleMouseDown(int row, MouseEventArgs args)
    {
        OnMouseDown.InvokeAsync(new RowMouseEventArgs(row, args));
    }

    private void HandleMouseOver(int row, MouseEventArgs args)
    {
        OnMouseOver.InvokeAsync(new RowMouseEventArgs(row, args));
    }

}